package com.gomcarter.frameworks.mybatis.factory;

import com.alibaba.druid.pool.DruidDataSource;
import com.gomcarter.frameworks.mybatis.datasource.ReadWriteDataSource;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class ReadWriteDataSourceBuilder {

    public static void createDataSource(ReadWriteDataSource readWriteDataSource, Properties properties) throws Exception {
        //初始化主库
        String writePrefix = "write", readPrefix = "read";
        DruidDataSource write = createDataSource(properties,
                writePrefix,
                properties.getProperty(writePrefix + "JdbcUrl"),
                properties.getProperty(writePrefix + "JdbcUser"),
                properties.getProperty(writePrefix + "JdbcPassword")
        );

        readWriteDataSource.setWriteDataSource(write);
        String splitter = "\\|";
        // 如果没有配置读库，那么默认读库使用主库
        if (properties.getProperty(readPrefix + "JdbcUrl") == null) {
            readPrefix = writePrefix;
        }

        String[] readUrls = properties.getProperty(readPrefix + "JdbcUrl").split(splitter),
                users = properties.getProperty(readPrefix + "JdbcUser").split(splitter),
                passwords = properties.getProperty(readPrefix + "JdbcPassword").split(splitter);
        Map<String, DataSource> readDataSourceMap = new HashMap<>();
        for (int i = 0; i < readUrls.length; ++i) {
            readDataSourceMap.put("readDataSource" + i, createDataSource(properties, readPrefix, readUrls[i], users[i], passwords[i]));
        }
        readWriteDataSource.setReadDataSourceMap(readDataSourceMap);
        readWriteDataSource.afterPropertiesSet();
    }

    private static int valueOf(String value, int defaultValue) {
        try {
            return Integer.parseInt(value);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    private static DruidDataSource createDataSource(Properties properties, String prefix, String url, String username, String password) throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setInitialSize(valueOf(properties.getProperty(prefix + "JdbcInitialSize"), 1));
        dataSource.setMaxActive(valueOf(properties.getProperty(prefix + "JdbcMaxActive"), 20));
        dataSource.setMinIdle(valueOf(properties.getProperty(prefix + "JdbcMinIdle"), 10));
        dataSource.setMaxWait(valueOf(properties.getProperty(prefix + "JdbcMaxWait"), 30000));
        dataSource.setMinEvictableIdleTimeMillis(valueOf(properties.getProperty(prefix + "JdbcMinEvictableIdleTimeMillis"), 3000000));
        dataSource.setValidationQuery(properties.getProperty(prefix + "JdbcValidationQuery", "SELECT 1"));
        dataSource.setTestWhileIdle(Boolean.parseBoolean(properties.getProperty(prefix + "JdbcTestWhileIdle", "true")));
        dataSource.setTestOnBorrow(Boolean.parseBoolean(properties.getProperty(prefix + "JdbcTestOnBorrow", "false")));
        dataSource.setTestOnReturn(Boolean.parseBoolean(properties.getProperty(prefix + "JdbcTestOnReturn", "false")));
        dataSource.setTimeBetweenEvictionRunsMillis(valueOf(properties.getProperty(prefix + "JdbcTimeBetweenEvictionRunsMillis"), 3000));
        dataSource.setRemoveAbandoned(Boolean.parseBoolean(properties.getProperty(prefix + "JdbcRemoveAbandoned", "false")));
        dataSource.setRemoveAbandonedTimeout(valueOf(properties.getProperty(prefix + "JdbcRemoveAbandonedTimeout"), 1800));
        dataSource.setLogAbandoned(Boolean.parseBoolean(properties.getProperty(prefix + "JdbcLogAbandoned", "true")));
        dataSource.setFilters(properties.getProperty(prefix + "JdbcFilters"));
        String connectionInitSqls = properties.getProperty(prefix + "JdbcConnectionInitSqls");
        if (connectionInitSqls != null) {
            dataSource.setConnectionInitSqls(Arrays.asList(connectionInitSqls.split("\\|")));
        }
        dataSource.init();
        return dataSource;
    }

    public static void destroy(ReadWriteDataSource dataSource) {
        if (dataSource != null) {
            DataSource write = dataSource.getWriteDataSource();
            if (write instanceof DruidDataSource) {
                ((DruidDataSource) write).setBreakAfterAcquireFailure(true);
                ((DruidDataSource) write).close();
            }

            Map<String, DataSource> readDataSourceMap = dataSource.getReadDataSourceMap();
            if (readDataSourceMap != null) {
                readDataSourceMap.values().stream()
                        .filter(read -> read instanceof DruidDataSource)
                        .forEach(read -> {
                            ((DruidDataSource) read).setBreakAfterAcquireFailure(true);
                            ((DruidDataSource) read).close();
                        });
            }
        }
    }
}
